home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- * Purpose:
- * Eliminate part of the image. Bounding region can be a rectangular
- * or a circular region (to be implemented).
- *
- * Limitations:
- * only the viewable region is croppable.
- */
-
- #if !defined(lint) && defined(F_ID)
- char *id_crop = "$Id: crop.c,v 0.91 1994/02/20 00:53:01 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "extern.h"
-
- /******************* defines and limits **********************/
-
- #define CMAX 50 /* max border thru pop-pup */
- #define CROSSL 16 /* cross lenght */
-
- /******************* local variables ***************************/
-
- static Rect_t imgbound, *ibr; /* input image region */
- static Rect_t regbound, *cbr; /* current crop region */
- static int bcolor = 1; /* rubber color */
- static int cobjs; /* region defs */
- static int ioffx, ioffy; /* input & current image loc diff */
- static int offx, offy; /* distance from (x,y) to image */
- static int croped; /* true if image is altered */
- static IPTR oim; /* local copy of image ptr */
-
- /****************** local functions **************************/
-
- static int crop_init(IPTR, int);/* initialize */
- static int crop_finish(IPTR); /* clean up */
- static int crop_it(IPTR); /* do the cropping */
- static int crop_popup(IPTR); /* handle popup */
- static void crop_undo(IPTR); /* Undo last crop */
- static void crop_save(IPTR); /* change image */
- static void crop_add_frame(int);/* enlarge region */
- static void ras_fill(IPTR, int *);
-
-
- /********************************************************************
- * Global entry point for cropping.
- *
- *******************************************************************/
-
- int
- do_crop(IPTR im)
- {
- int done;
- short val;
- long dev;
-
- /* initial rubber band position and size */
-
- if (crop_init(im, 0) < 0)
- return -1;
-
- /* how to handle window manager's resizing, re-position etc */
-
- install_wm_handler(crop_init);
-
- /* make a local copy for undo */
-
- if ((oim = img_dup(im)) == 0)
- {
- Bark("Crop", "Can't save image");
- return -1;
- }
-
- /*
- * loop until cancel or done, which is set either by ESC key or by popup
- * entry
- */
- croped = done = 0;
- do
- {
- dev = rubber_info(win_id, &val, &cbr->x, &cbr->y,
- &cbr->w, &cbr->h, bcolor, CROSSL);
-
- /*
- * remember current location relative to lower left corner of the
- * image. Need this info for window manager repaint events
- */
-
- offx = cbr->x - im->xi;
- offy = cbr->y - im->yi;
-
- ioffx = ibr->x - im->xi;
- ioffy = ibr->y - im->yi;
-
- switch (bit_handle_event(dev, val))
- {
- case KEYBD:
- done = (val == 27) ? -1 : 0;
- break;
- case ESCKEY:
- done = (val > 0) ? -1 : 0;
- break;
- case MENUBUTTON:
- done = val && crop_popup(im);
- break;
- default:
- M_info("Crop", "Unknown event %ld %d", dev, val);
- break;
- }
- }
- while (!done);
-
- rubber_finish();
-
- if (done == -1) /* cancel */
- crop_undo(im);
-
- return crop_finish(im);
- }
-
- /**************************************************************
- * Initialize the CROP function: initial size and location
- * of the rubber band. This function also handles window resizing,
- * reposition events (as far as rubber band location is concerned.
- *****************************************************************/
-
- /*ARGSUSED */
- static int
- crop_init(IPTR im, int wme)
- {
-
- /* default limit is the larger of the window & image */
-
- set_rubber_bounds(0, Min(1, im->xi - 1), Min(1, im->yi - 1),
- Max(win_w - 1, im->w + 2),
- Max(win_h - 1, im->h + 2));
-
-
- if (wme)
- {
- /*
- * true wme indicates there is a possibility that window might be
- * reszied. Figure out there the new rubber band should be where it
- * has a constant relationship to image
- */
-
- cbr->x = im->xi + offx;
- cbr->y = im->yi + offy;
-
- /*
- * must not use im->xi & im->yi as the filling bounds are against
- * the OLD image bounds, not the stuff after internal filling. This
- * is relevent only redraw occurs while in color selection routine
- */
-
- ibr->x = im->xi + ioffx;
- ibr->y = im->yi + ioffy;
-
- }
- else
- {
- ibr = &imgbound;
- cbr = ®bound;
-
- set_rect(ibr, im->xi, im->yi, im->w, im->h);
-
- /* initial size, default to viewable region */
- copy_rect(cbr, union_rect(make_rect(1, 1, win_w, win_h), ibr));
-
- offx = offy = ioffx = ioffy = 0;
-
- /* make the box larger by one pixel on all sides */
- shift_rect(cbr, -1, -1);
- inc_rect(cbr, 2, 2);
-
- /*
- * must turn old polygon fill on as otherwise 1pixel sized fill is
- * wrong
- */
-
- set_current_window(win_id);
- glcompat(GLC_OLDPOLYGON, 1);
-
- }
-
- return 0;
- }
-
- /************************************************************
- * Undo all changes made so far
- ************************************************************/
- static void
- crop_undo(IPTR im)
- {
- if (croped)
- {
- /* can't use img_dup, ineffectual upon return */
- img_dup_raster(im, oim);
- im->ok = 1;
-
- /* once undo, text ok to be displayed again */
- im->io->display = Generic_display;
- im->io->display(im, 0, 1);
-
- crop_init(im, 0);
- croped = 0;
- update_image_info(im);
- }
- }
-
- /***************************************************************
- * make all change permenent
- ***************************************************************/
-
- static void
- crop_save(IPTR im)
- {
- if (croped)
- {
- free_image(oim);
- oim = img_dup(im);
-
- del_text();
- del_marking();
-
- /* re-initialize the position */
- crop_init(im, 0);
-
- croped = 0;
- }
- }
-
- /*********************************************************
- * make crop region n pixels larger
- *******************************************************/
- static void
- interactive_frame(void)
- {
- static int fw = 3; /* frame width */
- int xt1, yt1, tw, th, cc;
-
- do
- {
- xt1 = cbr->x - fw;
- yt1 = cbr->y - fw;
- tw = cbr->w + 2 * fw;
- th = cbr->h + 2 * fw;
- set_current_window(win_id);
- rubber_moveto(&xt1, &yt1, &tw, &th);
- }
- while (!(cc = getint("Enter FrameWidth:", &fw, -CMAX, CMAX, 1)));
-
-
- if (cc >= 0) /* not cancel */
- {
- set_rect(cbr, xt1, yt1, tw, th);
- }
- }
-
-
- static void
- crop_add_frame(int n)
- {
-
- if (n < 3)
- {
- shift_rect(cbr, -n, -n);
- inc_rect(cbr, 2 * n, 2 * n);
- }
- else
- {
- interactive_frame();
- }
-
- set_current_window(win_id);
- rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
- }
-
-
- /************************************************************
- * crop pop-up menu routines: If cancel, return -1, done 1
- * else zero;
- **************************************************************/
- static int
- crop_popup(IPTR im)
- {
- static long cmenu = -1;
- static char *menu =
- "Crop%t|DoIt|Help|BdColor|Objs|Frame1|Frame2|FrameN|"
- "Auto|Save|Undo|Cancel|Done";
- int done = 0, cc;
- int bot, left, top, right;
-
- /* if menu has not been made yet, make it now */
- if (cmenu < 0)
- cmenu = defpup(menu);
-
- switch ((cc = dopup(cmenu)))
- {
- case 1: /* crop */
- done = (crop_it(im) < 0);
- rubber_show(bcolor);
- break;
- case 2: /* help */
- help_cb((void *) 0, HELP_CROP);
- break;
- case 3: /* rubber color */
- ++bcolor;
- bcolor %= over_pup_colors;
- rubber_show(bcolor);
- break;
- case 4: /* rubber object */
- ++cobjs;
- cobjs %= get_max_rubber_obj();
- set_rubber_obj(cobjs);
- rubber_show(bcolor);
- break;
- case 5: /* 1 pixel larger */
- case 6: /* 2 pixel larger */
- case 7: /* n-pixel larger */
- crop_add_frame(cc - 4);
- break;
- case 8: /* auto */
- if (img_get_border(im, &bot, &left, &top, &right, 1))
- break;
-
- set_rect(ibr, ibr->x + left, ibr->y + bot,
- (im->w + 2) - left - right,
- (im->h + 2) - top - bot);
- set_current_window(win_id);
- rubber_moveto(&cbr->x, &cbr->y, &cbr->w, &cbr->h);
- break;
- case 9: /* save */
- crop_save(im);
- break;
- case 10: /* undo */
- crop_undo(im);
- break;
- case 11: /* undo and return */
- crop_undo(im);
- done = -1;
- break;
- case 12:
- done = 1;
- break;
- }
- return done;
- }
-
- /*******************************************************************
- * Gotten the crop region icb and corresponding raster matrix m,
- * insert into image structure
- *******************************************************************/
-
- static void
- crop_update(IPTR im, void *m, Rect_t * icb)
- {
-
- /* update the image structure */
- im->w = icb->w;
- im->h = icb->h;
-
- fill_image_struct(im, m, im->h, im->w, im->type);
-
- /* supress centering */
- im->xi = icb->x;
- im->yi = icb->y;
- im->xf = icb->x + icb->w - 1;
- im->yf = icb->y + icb->h - 1;
- }
-
- /*******************************************************************
- * Cropping by core raster manipualtions.
- * If there are text or sgfs on screen, framebuffer read can not be
- * avoided because lack of background rendering support (No Pixmap) in GL.
- * Well, can't change that.
- *
- * For regions outside the image, screen will be read and may be
- * refilled later.
- *
- ********************************************************************/
- static int
- ras_crop(IPTR im)
- {
- void *m, *om = 0;
- Rect_t cb;
- const Rect_t *iu, *ir = img_rect(im);
- Rect_t *icb = &cb;
-
- /* get the interior of the bounding region */
-
- copy_rect(icb, cbr);
- shift_rect(icb, 1, 1);
- inc_rect(icb, -2, -2);
-
- M_info("Crop", "Internal cropping");
- show_busy(0);
-
-
- /*
- * if crop region is completely within image, the piece of the image,
- * corresponding to the crop region will be the current image. Much
- * faster than the mixed regions.
- */
-
- if (cover_rect(ir, icb))
- {
- m = equal_rect(ir, icb) ?
- im->mraster : get_subimage(im, icb->x, icb->y, icb->w, icb->h);
- crop_update(im, m, icb);
- if (m != im->mraster)
- free_mat(m);
- end_busy();
- return 0;
- }
-
- /*
- * mixed regions. Always read frame buffer first and then insert the
- * raster corresponding to crop region from core directly into new image
- * matrix
- */
-
- if (!(m = get_mat(icb->h, icb->w, im->esize)))
- return -1;
-
- Rectread(icb->x, icb->y,
- icb->x + icb->w - 1, icb->y + icb->h - 1, ((char **) m)[0]);
-
- /* get the union of the two regions */
- if ((iu = union_rect(ir = img_rect(im), icb)))
- {
- om = equal_rect(ir, iu) ?
- im->mraster : get_subimage(im, iu->x, iu->y, iu->w, iu->h);
- put_submat(m, icb->h, icb->w, om, iu->y - icb->y,
- iu->x - icb->x, iu->h, iu->w, im->esize);
- }
- else
- {
- M_warn("Crop", "No union found");
-
- }
-
- if (om && om != im->mraster)
- free_mat(om);
-
- crop_update(im, m, icb);
- end_busy();
-
- return 0;
- }
-
- /*********************************************************************
- * Cropping via framebuffer read. Could look bad if on Indigoes
- * or machines with less than 24 bits framebuffer
- ********************************************************************/
-
- static int
- fb_crop(IPTR im)
- {
- /* the bounding rect is 1 pixel larger than both sides */
- return read_screen(im, cbr->x + 1, cbr->y + 1, cbr->w - 2, cbr->h - 2);
- }
-
- /*******************************************************************
- * When the cropping region is larger than current image, have a choice
- * to fill the empty regions. This function does the interactive
- * part of the filling. The actually filling is done by memory copy
- * in crop_it
- *******************************************************************/
-
- /* default fill color */
- static int lc[4] =
- {
- 0, 0, 0, 0
- };
-
- /***************************************************************
- * Fill the region that is not the union of (x,y, bw, bh)
- * and (xi, yi, xf, yf)
- **************************************************************/
- static void
- screen_fill_only(void)
- {
- int fx2 = cbr->x + cbr->w - 1;
- int fy2 = cbr->y + cbr->h - 1;
- int xf = ibr->x + ibr->w - 1;
- int yf = ibr->y + ibr->h - 1;
-
- if (union_rect(ibr, cbr) == 0)
- {
- rectfi(cbr->x, cbr->y, cbr->x + cbr->w - 1, cbr->y + cbr->h - 1);
- return;
- }
-
- if (cbr->x < ibr->x - 1)
- {
- rectfi(cbr->x + 1, cbr->y + 1, ibr->x - 1, fy2 - 1);
- }
-
- if (cbr->y < ibr->y - 1)
- {
- rectfi(cbr->x + 1, cbr->y + 1, fx2 - 1, ibr->y - 1);
- }
-
- if (fx2 > xf + 1)
- {
- rectfi(xf + 1, cbr->y + 1, fx2 - 1, fy2 - 1);
- }
-
- if (fy2 > yf + 1)
- {
- rectfi(cbr->x + 1, yf + 1, fx2 - 1, fy2 - 1);
- }
- }
-
- /**********************************************************************
- * Fill and show it
- *********************************************************************/
- static void
- screen_fill(int c[])
- {
- set_current_window(win_id);
- reshapeviewport();
-
- Color((RGB2CPACK(c[0], c[1], c[2])), c[3]);
- screen_fill_only();
-
- if (double_buf)
- {
- swapbuffers();
- screen_fill_only();
- }
- }
-
-
- /*********************************************************************
- * Similar to screen_fill, but fill the raster instead as well
- ********************************************************************/
- static void
- ras_fill(IPTR im, int *c)
- {
- void *m = im->mraster;
- size_t e = im->esize;
- rgba_t fc;
- int delta;
- int x2 = cbr->x + cbr->w - 1;
- int y2 = cbr->y + cbr->h - 1;
- int iw = im->w, ih = im->h;
- int xf = ibr->x + ibr->w - 1;
- int yf = ibr->y + ibr->h - 1;
-
-
- if (c == 0)
- c = lc;
-
- fc = (IS_CI(im)) ? c[3] : (rgba_t) Pack(c[0], c[1], c[2]);
-
- #if 1
- /* completely disjoint */
- if (union_rect(ibr, img_rect(im)) == 0)
- {
- init_mat(im->mraster, im->h, im->w, im->esize, fc);
- screen_fill(c);
- return;
- }
- #endif
- /* fill_submat uses ( r = r1; r<=r2; r++) */
- if ((delta = Min(ibr->x, x2 - 1) - cbr->x - 1) > 0)
- {
- fill_submat(m, 0, ih - 1, 0, delta - 1, fc, e);
- }
-
- if ((delta = Min(ibr->y, yf - 1) - cbr->y - 1) > 0)
- {
- fill_submat(m, 0, delta - 1, 0, iw - 1, fc, e);
- }
-
- if ((delta = x2 - 1 - Max(xf, cbr->x + 1)) > 0)
- {
- fill_submat(m, 0, ih - 1, iw - delta, iw - 1, fc, e);
- }
-
- if ((delta = y2 - 1 - Max(yf, cbr->y + 1)) > 0)
- {
- fill_submat(m, ih - delta, ih - 1, 0, iw - 1, fc, e);
- }
-
- /* also show on screen */
- screen_fill(c);
- }
-
- /******************************************************************
- * actually doing the crop by calling other routine if necessary
- ********************************************************************/
- static int
- crop_it(IPTR im)
- {
- short val;
- int internal, fill;
- Rect_t trect;
-
- #ifdef MTRACE
- M_trace("CropIt", "Entering");
- #endif
-
- rubber_hide();
-
- /* true region is 1pixel larger on all sides */
- copy_rect(&trect, cbr);
- shift_rect(&trect, 1, 1);
- inc_rect(&trect, -2, -2);
-
- set_current_window(win_id);
-
- frontbuffer(1);
- clear_outside_rect(&trect);
-
- /* disable text & sgf displaying */
- im->io->display = display_image;
-
- /* replace raster if no text and sgfs */
-
- internal = (!always_readscrn && !number_of_text() && !number_of_sgf());
- set_current_window(win_id);
- reshapeviewport();
-
- if ((internal ? ras_crop : fb_crop) (im) < 0)
- return -1;
-
- update_image_info(im);
-
- /* fill if neccessary. crop_fill == 0 turns off fill */
-
- fill = (!cover_rect(ibr, &trect) && (crop_fill == 2 ||
- (crop_fill == 1 && yes_no("FillCropRegion", "", "Fill ?", 0))));
-
- /* do redraw and eat other events */
-
- (void) bit_qread(&val);
-
- /*
- * remember where the bounds and old image locatations relative to
- * cropped image. Useful if redraw occurs to re-display rubber band
- */
-
- ioffx = ibr->x - im->xi;
- ioffy = ibr->y - im->yi;
-
- offx = cbr->x - im->xi;
- offy = cbr->y - im->yi;
-
- if (fill)
- {
-
- /* show default color */
- ras_fill(im, lc);
-
- /* what to do if color changes */
- set_getcolor_cb(screen_fill);
-
- /*
- * never returns unless form is finished. For every color change,
- * screen_fill will be called
- */
-
- get_color(im, lc, 1); /* block */
-
- /*
- * could stick the following into screen_fill, but it could be
- * slow. This way although if unknown repaints occurs, the screen
- * could be messed up, but the image is not damaged and we have a
- * much better response
- */
-
- /*
- * do final actually filling. It is always a good thing to fill
- * internally
- */
- ras_fill(im, lc);
- }
- croped = 1;
- frontbuffer(!double_buf);
-
- #ifdef MTRACE
- M_trace("CropIt", "Returning");
- #endif
- return 0;
- }
-
- /**********************************************************************
- * clean up
- **********************************************************************/
- static int
- crop_finish(IPTR im)
- {
-
- if (im->ok > 0)
- {
- free_image(oim);
- }
- else
- {
- Bark("Crop", "Something is not right");
- free_image_mem(im);
- memcpy(im, oim, sizeof(*oim));
- croped = 0;
- }
-
- im->ok = 1;
- if (croped)
- {
- if (!keepmisc)
- {
- del_text();
- del_marking();
- }
- im->io->display(im, -1, 1);
- }
-
- /*
- * since there is no mask set, if framebuffer is read, we got full
- * 12bits, need to mask off the un-used one otherwise colormap overflown.
- */
-
- if (IS_CI(im))
- do_ci_mask(im->raster, im->w * im->h, im->cmap->colors - 1);
-
- remove_wm_handler(crop_init);
-
- im->io->display = Generic_display;
-
- if (double_buf)
- im->io->display(im, 0, 1);
-
- return 0;
- }
-